# Scroll Container Context

## Examples


### Provider

A Dropdown inside a custom Scroll Container. The Dropdown (when open) scrolls with the custom container, not the window.

```typescript
import React, { useCallback, useState } from 'react';

import Button from '@splunk/react-ui/Button';
import Dropdown from '@splunk/react-ui/Dropdown';
import P from '@splunk/react-ui/Paragraph';
import { ScrollContainerProvider } from '@splunk/react-ui/ScrollContainerContext';


function Provider() {
    const [scrollContainer, setScrollContainer] = useState<HTMLDivElement | null>();
    const scrollContainerRef = useCallback((el: HTMLDivElement | null) => {
        setScrollContainer(el);
    }, []);

    const toggle = <Button label="Open dropdown in custom container" isMenu />;
    return (
        <div
            ref={scrollContainerRef}
            style={{
                border: '1px dashed #ccc',
                height: '100px',
                width: '500px',
                margin: '20px 20px 0px 0px',
                padding: '30px 20px 10px 20px',
                overflow: 'scroll',
            }}
        >
            <ScrollContainerProvider value={scrollContainer}>
                <Dropdown retainFocus toggle={toggle}>
                    <P style={{ padding: 20, maxWidth: 300 }}>
                        This dropdown is inside a custom scroll container.
                    </P>
                </Dropdown>
                <P style={{ marginTop: 20 }}>Scroll to see more content.</P>
                <P>Additional content for demonstration.</P>
            </ScrollContainerProvider>
        </div>
    );
}

export default Provider;
```



### measureProgress

```typescript
import React, { useCallback, useContext, useEffect, useState } from 'react';

import P from '@splunk/react-ui/Paragraph';
import {
    ScrollContainerContext,
    ScrollContainerProvider,
} from '@splunk/react-ui/ScrollContainerContext';

type Container = Document | HTMLElement | Window;

function measureProgress(scrollContainer: Container): number {
    const measureEl =
        scrollContainer instanceof HTMLElement ? scrollContainer : document.documentElement;
    const height = measureEl.scrollHeight - measureEl.clientHeight;
    const elasticProgress = height === 0 ? 0 : measureEl.scrollTop / height;
    const progress = Math.min(Math.max(elasticProgress, 0), 1);
    return Math.round(progress * 100);
}


function ScrollProgress() {
    const scrollContainer: Document | HTMLElement | Window =
        useContext(ScrollContainerContext) || window;
    const [progress, setProgress] = useState(0);

    const updateProgress = useCallback(() => {
        setProgress(measureProgress(scrollContainer));
    }, [scrollContainer]);

    useEffect(updateProgress, [scrollContainer, updateProgress]);

    useEffect(() => {
        scrollContainer.addEventListener('scroll', updateProgress);

        return () => {
            scrollContainer.removeEventListener('scroll', updateProgress);
        };
    }, [scrollContainer, updateProgress]);

    return <P>Scroll progress: {progress}%</P>;
}

function Consumer() {
    const [scrollContainer, setScrollContainer] = useState<HTMLDivElement | null>();
    const scrollContainerRef = useCallback((el: HTMLDivElement | null) => {
        setScrollContainer(el);
    }, []);

    return (
        <>
            <ScrollContainerProvider value={scrollContainer}>
                <ScrollProgress />
            </ScrollContainerProvider>
            <div
                ref={scrollContainerRef}
                style={{
                    border: '1px dashed #ccc',
                    height: '100px',
                    width: '500px',
                    margin: '20px 20px 0px 0px',
                    padding: '30px 20px 10px 20px',
                    overflow: 'scroll',
                }}
            >
                <ScrollContainerProvider value={scrollContainer}>
                    <P>This is the first paragraph in the scroll container.</P>
                    <P>This is the second paragraph in the scroll container.</P>
                    <P>This is the third paragraph in the scroll container.</P>
                    <P>This is the fourth paragraph in the scroll container.</P>
                    <P>This is the fifth paragraph in the scroll container.</P>
                </ScrollContainerProvider>
            </div>
        </>
    );
}

export default Consumer;
```




## API

import React from 'react';

import UtilAPI from '@splunk/react-docs/UtilAPI';

import docs from '!!@splunk/jsdoc-loader!@splunk/react-ui/ScrollContainerContext/ScrollContainerContext';

function DevelopSection() {
    return [<UtilAPI key="ScrollContainerContext" docs={docs} />];
}

export default DevelopSection;


